var plc = require('./plc.js');

var Accessory, Service, Characteristic, UUIDGen;

module.exports = function (homebridge) {
    Accessory = homebridge.platformAccessory;
    Service = homebridge.hap.Service;
    Characteristic = homebridge.hap.Characteristic;
    UUIDGen = homebridge.hap.uuid;
    homebridge.registerPlatform("homebridge-plc-rs485", "plc", plcPlatform);
}

function plcPlatform(log, config, api) {
    this.log = log;
    this.config = config || {"platform": "plc"};
    this.nodes = this.config.nodes || [];

    this.accessories = {};
    this.polling = {};

    this.dev = this.config.dev || "/dev/ttyS0";
    this.baudrate = this.config.baudrate || 9600;
    this.interval = parseInt(this.config.interval, 10) || 100;
    if (api) {
        this.api = api;
        this.api.on('didFinishLaunching', this.didFinishLaunching.bind(this));
    }
    PLC = new plc(this.dev,this.baudrate,log);
}

// Method to restore accessories from cache
plcPlatform.prototype.configureAccessory = function (accessory) {
    this.setService(accessory);
    this.accessories[accessory.context.name] = accessory;
}


// Method to setup listeners for different events
plcPlatform.prototype.setService = function (accessory) {
    var service = accessory.context.type == "lightbulb" ? Service.Lightbulb : Service.Switch;
    accessory.getService(service)
        .getCharacteristic(Characteristic.On)
        .on('get', this.getPowerState.bind(this, accessory.context))
        .on('set', this.setPowerState.bind(this, accessory.context));

    accessory.on('identify', this.identify.bind(this, accessory.context));
}

// Method to setup accesories from config.json
plcPlatform.prototype.didFinishLaunching = function () {

    // Add or update accessories defined in config.json
    for (var i in this.nodes) this.addAccessory(this.nodes[i]);

    // Remove extra accessories in cache
    for (var name in this.accessories) {
        var accessory = this.accessories[name];
        if (!accessory.reachable) this.removeAccessory(accessory);
    }
}

// Method to add and update HomeKit accessories
plcPlatform.prototype.addAccessory = function (data) {
    data.type = data.type.toString();
    data.name = data.room.toString() + data.name.toString();
    this.log("Initializing platform accessory '" + data.name + "'...");

    // Retrieve accessory from cache
    var accessory = this.accessories[data.name];
    if (!accessory) {
        // Setup accessory as SWITCH (8) category.
        var uuid = UUIDGen.generate(data.name);

        accessory = new Accessory(data.name, uuid, 8);

        // Setup HomeKit switch service
        var service = data.type == "lightbulb" ? Service.Lightbulb : Service.Switch ;

        accessory.addService(service, data.name);

        // New accessory is always reachable
        accessory.reachable = true;

        // Setup listeners for different switch events
        accessory.context.type =data.type;
        this.setService(accessory);

        // Register new accessory in HomeKit
        this.api.registerPlatformAccessories("homebridge-plc-rs485", "plc", [accessory]);

        // Store accessory in cache
        this.accessories[data.name] = accessory;
    }

    // Confirm variable type

 
    data.address = data.address;
    data.channel = data.channel;
    if (data.manufacturer) data.manufacturer = data.manufacturer.toString();
    if (data.model) data.model = data.model.toString();
    if (data.serial) data.serial = data.serial.toString();

    // Store and initialize variables into context
    var cache = accessory.context;
    cache.name =  data.name;
    cache.type = data.type;
    cache.address = data.address;
    cache.channel = data.channel;
    cache.manufacturer = data.manufacturer;
    cache.model = data.model;
    cache.serial = data.serial;
    if (cache.state === undefined) {
        cache.state = false;
    }
    this.log(cache);
    // Retrieve initial state
    this.getInitState(accessory);

    // Configure state polling
    this.statePolling(data.name);
}

// Method to remove accessories from HomeKit
plcPlatform.prototype.removeAccessory = function (accessory) {
    this.log("removeAccessory");
    if (accessory) {
        var name = accessory.context.name;
        this.log(name + " is removed from HomeBridge.");
        this.api.unregisterPlatformAccessories("homebridge-plc-rs485", "plc", [accessory]);
        delete this.accessories[name];
    }
}

// Method to retrieve initial state
plcPlatform.prototype.getInitState = function (accessory) {
    var manufacturer = accessory.context.manufacturer || "Default-Manufacturer";
    var model = accessory.context.model || "Default-Model";
    var serial = accessory.context.serial || "Default-SerialNumber";

    // Update HomeKit accessory information
    accessory.getService(Service.AccessoryInformation)
        .setCharacteristic(Characteristic.Manufacturer, manufacturer)
        .setCharacteristic(Characteristic.Model, model)
        .setCharacteristic(Characteristic.SerialNumber, serial);

    // Retrieve initial state if polling is disabled
    //if (!accessory.context.polling) {
    //    var service = accessory.context.type == "lightbulb" ? Service.Lightbulb :Service.Switch;
     //   accessory.getService(service)
    //        .getCharacteristic(Characteristic.On)
     //       .getValue();
    //}

    // Configured accessory is reachable
    accessory.updateReachability(true);
}

// Method to determine current state
plcPlatform.prototype.statePolling = function (name) {
  var self = this;
  var accessory = this.accessories[name];
  var thisLightbulb = accessory.context;

  // Clear polling
  clearTimeout(this.polling[name]);

   PLC.getState(thisLightbulb.address,thisLightbulb.channel, function (error, state) {
            // Update state if command exists
            thisLightbulb.state = state;
            var service = thisLightbulb.type == "lightbulb" ? Service.Lightbulb :Service.Switch;
            accessory.getService(service)
            .getCharacteristic(Characteristic.On)
            .getValue();
        });

  // Setup for next polling
  this.polling[name] = setTimeout(this.statePolling.bind(this, name), 2 * 1000);
}
// Method to determine current state
plcPlatform.prototype.getPowerState = function (thisLightbulb, callback) {
      var self = this;

        // Check state if polling is disabled
        PLC.getState(thisLightbulb.address,thisLightbulb.channel, function (error, state) {
            // Update state if command exists
            thisLightbulb.state = state;
            callback(error, thisLightbulb.state);
        });
    
}

// Method to set state
plcPlatform.prototype.setPowerState = function (thisLightbulb, state, callback) {
    if(state) {
        PLC.setOn(thisLightbulb.address,thisLightbulb.channel,function (error) {
            callback(error)
        });
    } else {
        PLC.setOff(thisLightbulb.address,thisLightbulb.channel,function (error) {
            callback(error)
        });
    }
}

// Method to handle identify request
plcPlatform.prototype.identify = function (thisLightbulb, paired, callback) {
    this.log(thisLightbulb.name + " identify requested!");
    callback();
}
